﻿#pragma once
#include <atomic>
#include <memory>
#include "zyEnvironment.h"


namespace DarkMoonUI {
	class zyObject {
	private:
		LPVOID m_pSelf;
		std::atomic_size_t m_refCount;

		FnWndProc m_fnWndProc;
		FnChildWndProc m_fnChildWndProc;
		FnDestroy m_fnDestroy;

		std::unique_ptr<std::unordered_map<std::wstring, LPVOID>> m_pPtrData;
		std::unique_ptr<std::unordered_map<std::wstring, std::wstring>> m_pStringData;
		std::unique_ptr<std::unordered_map<std::wstring, TRegEvent*>> m_pRegEvents;

		zyObject()
			: m_pSelf(this)
			, m_refCount(1)
			, m_fnWndProc(nullptr)
			, m_fnChildWndProc(nullptr)
			, m_fnDestroy(nullptr)
			, m_pPtrData(std::make_unique<std::unordered_map<std::wstring, LPVOID>>())
			, m_pStringData(std::make_unique<std::unordered_map<std::wstring, std::wstring>>())
			, m_pRegEvents(std::make_unique<std::unordered_map<std::wstring, TRegEvent*>>()) {
		}

		~zyObject() {
			m_pSelf = nullptr;
			releaseEventMap();
		}

		//disable copy constructor and assignment operator


	public:
		static zyObject* Create() { return new zyObject(); }

	public:
		void setWndProc(FnWndProc fnWndProc) { m_fnWndProc = fnWndProc; }
		void setChildWndProc(FnChildWndProc fnChildWndProc) { m_fnChildWndProc = fnChildWndProc; }
		void setDestroy(FnDestroy fnDestroy) { m_fnDestroy = fnDestroy; }

		LRESULT callWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL* bHandle) {
			if (m_fnWndProc)
				return m_fnWndProc(this, hWnd, uMsg, wParam, lParam, bHandle);
			return 0;
		}

		LRESULT callChildWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL* bHandle) {
			if (m_fnChildWndProc)
				return m_fnChildWndProc(this, hWnd, uMsg, wParam, lParam, bHandle);
			return 0;
		}

		void callDestroy() {
			if (m_fnDestroy)
				m_fnDestroy(this);
		}

		BOOL checkSelf() const { return m_pSelf == this; }

		size_t getRefCount() const { return m_refCount.load(std::memory_order_acquire); }

		size_t addRef() { return m_refCount.fetch_add(1, std::memory_order_release); };

		size_t release() {
			size_t count = m_refCount.fetch_sub(1, std::memory_order_acquire);
			if (count == 0) {
				if (m_fnDestroy)
					m_fnDestroy(this);
				delete this;
			}
			return count;
		}

		bool hasPtrData(const std::wstring& key) const { return m_pPtrData->find(key) != m_pPtrData->end(); }

		void setPtrData(const std::wstring& key, void* data) { (*m_pPtrData)[key] = data; }

		void* getPtrData(const std::wstring& key) const {
			if (!m_pPtrData)
				return nullptr;

			auto it = m_pPtrData->find(key);
			if (it != m_pPtrData->end()) {
				return it->second;
			}
			return nullptr;
		}

		void removePtrData(const std::wstring& key) { m_pPtrData->erase(key); }

		void setStringData(const std::wstring& key, const std::wstring& data) { (*m_pStringData)[key] = data; }

		std::wstring getStringData(const std::wstring& key) const {
			auto it = m_pStringData->find(key);
			if (it != m_pStringData->end()) {
				return it->second;
			}
			return L"";
		}

		void removeStringData(const std::wstring& key) { m_pStringData->erase(key); }

		TRegEvent* getRegEvent(const std::wstring& key) const {
			auto it = m_pRegEvents->find(key);
			if (it != m_pRegEvents->end()) {
				return it->second;
			}
			return nullptr;
		}

		void setRegEvent(const std::wstring& key, TRegEvent* pRegEvent) {
			TRegEvent* pOldEvent = getRegEvent(key);
			if (pOldEvent)
				delete pOldEvent;
			(*m_pRegEvents)[key] = pRegEvent;
		}

	private:
		void releaseEventMap() {
			if (!m_pRegEvents) return; // 确保 m_pRegEvents 不为空

			for (auto it = m_pRegEvents->begin(); it != m_pRegEvents->end(); ) {
				TRegEvent* pRegEvent = it->second;
				if (pRegEvent) {
					delete pRegEvent;
				}
				it = m_pRegEvents->erase(it); // erase 返回下一个有效的迭代器
			}
		}

	private:
		ZY_DISABLE_COPY_MOVE(zyObject); //防止Object對象被移動或複製
	};
}

// class zyObject {
// public:
//     zyObject() : m_refCount(new size_t(1)),
//                  m_pPtrData(new std::map<std::wstring, LPVOID>()),
//                  m_pStringData(new std::map<std::wstring, std::wstring>()) {}

//     zyObject(const zyObject& obj) : m_refCount(obj.m_refCount),
//                                     m_pPtrData(obj.m_pPtrData),
//                                     m_pStringData(obj.m_pStringData) { addRef(); }

//     ~zyObject() { release(); };

//     zyObject& operator=(const zyObject& obj) {
//         if (this != &obj) {
//             release();
//             m_refCount = obj.m_refCount;
//             m_pPtrData = obj.m_pPtrData;
//             m_pStringData = obj.m_pStringData;
//             addRef();
//         }
//         return *this;
//     }

//     size_t addRef() { return _InterlockedIncrement(m_refCount); };

//     size_t release() {
//         size_t count = _InterlockedDecrement(m_refCount);
//         if (count == 0) {
//             releaseHelper();
//             delete m_refCount;
//             delete m_pPtrData;
//             delete m_pStringData;
//         }
//         return count;
//     }

//     bool hasPtrData(const std::wstring& key) const { return m_pPtrData->find(key) != m_pPtrData->end(); }

//     void setPtrData(const std::wstring& key, void* data) { (*m_pPtrData)[key] = data; }

//     void* getPtrData(const std::wstring& key) const {
//         auto it = m_pPtrData->find(key);
//         if (it != m_pPtrData->end()) {
//             return it->second;
//         }
//         return nullptr;
//     }

//     void setStringData(const std::wstring& key, const std::wstring& data) { (*m_pStringData)[key] = data; }

//     std::wstring getStringData(const std::wstring& key) const {
//         auto it = m_pStringData->find(key);
//         if (it != m_pStringData->end()) {
//             return it->second;
//         }
//         return L"";
//     }

// private:
//     size_t* m_refCount;
//     std::map<std::wstring, LPVOID>* m_pPtrData;
//     std::map<std::wstring, std::wstring>* m_pStringData;

// private:
//     inline void zyBase_OnNCDestroy();

//     void releaseHelper() {
//         zyBase_OnNCDestroy();
//     }
// };

// class zyAppInfo {
// public:
//     static zyAppInfo& getInstance() {
//         static zyAppInfo instance;
//         return instance;
//     }

//     void dpiProcess(POINT& pt) {
//         if (!m_bEnableDpiProcess)
//             return;
//         static int dpi = getDpiForWindow();
//         pt.x = (LONG)(pt.x * dpi / 96.0);
//         pt.y = (LONG)(pt.y * dpi / 96.0);
//     }

//     void setModuleHandle(HINSTANCE hInst) {
//         m_hInst = hInst;
//     }

//     HINSTANCE getModuleHandle() {
//         if (m_hInst)
//             return m_hInst;
//         m_hInst = GetModuleHandle(NULL);
//         return m_hInst;
//     }

//     void setEnableDpiProcess(BOOL bEnable) {
//         m_bEnableDpiProcess = bEnable;
//     }

//     void addEventWnd(HWND hWnd, zyObject* pObj) {
//         m_wndEventMap[hWnd] = *pObj;
//     }

//     void removeEventWnd(HWND hWnd) {
//         m_wndEventMap.erase(hWnd);
//     }

//     zyObject* getEventObject(HWND hWnd) {
//         auto it = m_wndEventMap.find(hWnd);
//         if (it != m_wndEventMap.end()) {
//             return &it->second;
//         }
//         return nullptr;
//     }

// private:
//     HINSTANCE m_hInst;
//     BOOL m_bEnableDpiProcess;

//     std::map<HWND, zyObject> m_wndEventMap;

// private:
//     zyAppInfo() : m_hInst(NULL), m_bEnableDpiProcess(TRUE) {}
//     ~zyAppInfo() {}

//     inline int getDpiForWindow() {
//         HDC hdc = GetDC(NULL);
//         int dpiX = GetDeviceCaps(hdc, LOGPIXELSX);
//         int dpiY = GetDeviceCaps(hdc, LOGPIXELSY);
//         return (((dpiX) > (dpiY)) ? (dpiX) : (dpiY));
//     }
// };

// void zyObject::zyBase_OnNCDestroy() {
//     auto hWnd = (HWND)getPtrData(L"hWnd");
//     if (hWnd) {
//         LONG_PTR oldWndProc = GetWindowLongPtr(hWnd, GWLP_WNDPROC);
//         if (oldWndProc)
//             SetWindowLongPtr(hWnd, GWLP_WNDPROC, oldWndProc);
//         zyAppInfo::getInstance().removeEventWnd(hWnd);
//     }
//     auto pLayout = (zyObject*)getPtrData(L"zyLayout");
//     if (pLayout)
//         delete pLayout;
// }